/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 *    ResultProducer.java
 *    Copyright (C) 1999-2012 University of Waikato, Hamilton, New Zealand
 *
 */

package weka.experiment;

import java.io.Serializable;

import weka.core.Instances;

/**
 * This interface defines the methods required for an object that produces
 * results for different randomizations of a dataset.
 * <p>
 *
 * Possible implementations of ResultProducer: <br>
 * <ul>
 * <li>Random test/train splits
 * <li>CrossValidation splits
 * <li>LearningCurve splits (multiple results per run?)
 * <li>Averaging results of other result producers
 * </ul>
 *
 * @author Len Trigg (trigg@cs.waikato.ac.nz)
 * @version $Revision$
 */

public interface ResultProducer extends Serializable {

    /**
     * Sets the dataset that results will be obtained for.
     *
     * @param instances a value of type 'Instances'.
     */
    void setInstances(Instances instances);

    /**
     * Sets the object to send results of each run to.
     *
     * @param listener a value of type 'ResultListener'
     */
    void setResultListener(ResultListener listener);

    /**
     * Sets a list of method names for additional measures to look for in
     * SplitEvaluators.
     * 
     * @param additionalMeasures a list of method names
     */
    void setAdditionalMeasures(String[] additionalMeasures);

    /**
     * Prepare to generate results. The ResultProducer should call preProcess(this)
     * on the ResultListener it is to send results to.
     *
     * @exception Exception if an error occurs during preprocessing.
     */
    void preProcess() throws Exception;

    /**
     * Perform any postprocessing. When this method is called, it indicates that no
     * more requests to generate results for the current experiment will be sent.
     * The ResultProducer should call preProcess(this) on the ResultListener it is
     * to send results to.
     *
     * @exception Exception if an error occurs
     */
    void postProcess() throws Exception;

    /**
     * Gets the results for a specified run number. Different run numbers correspond
     * to different randomizations of the data. Results produced should be sent to
     * the current ResultListener, but only if the ResultListener says the result is
     * required (it may already have that result). A single run may produce multiple
     * results.
     *
     * @param run the run number to generate results for.
     * @exception Exception if a problem occurs while getting the results
     */
    void doRun(int run) throws Exception;

    /**
     * Gets the keys for a specified run number. Different run numbers correspond to
     * different randomizations of the data. Keys produced should be sent to the
     * current ResultListener
     *
     * @param run the run number to get keys for.
     * @exception Exception if a problem occurs while getting the keys
     */
    void doRunKeys(int run) throws Exception;

    /**
     * Gets the names of each of the key columns produced for a single run. The
     * names should not contain spaces (use '_' instead for easy translation.)
     *
     * @return an array containing the name of each key column
     * @exception Exception if the key names could not be determined (perhaps
     *                      because of a problem from a nested sub-resultproducer)
     */
    String[] getKeyNames() throws Exception;

    /**
     * Gets the data types of each of the key columns produced for a single run.
     *
     * @return an array containing objects of the type of each key column. The
     *         objects should be Strings, or Doubles.
     * @exception Exception if the key types could not be determined (perhaps
     *                      because of a problem from a nested sub-resultproducer)
     */
    Object[] getKeyTypes() throws Exception;

    /**
     * Gets the names of each of the result columns produced for a single run. The
     * names should not contain spaces (use '_' instead for easy translation.)
     *
     * @return an array containing the name of each result column
     * @exception Exception if the result names could not be determined (perhaps
     *                      because of a problem from a nested sub-resultproducer)
     */
    String[] getResultNames() throws Exception;

    /**
     * Gets the data types of each of the result columns produced for a single run.
     *
     * @return an array containing objects of the type of each result column. The
     *         objects should be Strings, or Doubles.
     * @exception Exception if the result types could not be determined (perhaps
     *                      because of a problem from a nested sub-resultproducer)
     */
    Object[] getResultTypes() throws Exception;

    /**
     * Gets a description of the internal settings of the result producer,
     * sufficient for distinguishing a ResultProducer instance from another with
     * different settings (ignoring those settings set through this interface). For
     * example, a cross-validation ResultProducer may have a setting for the number
     * of folds. For a given state, the results produced should be compatible.
     * Typically if a ResultProducer is an OptionHandler, this string will represent
     * those command line arguments required to set the ResultProducer to that
     * state.
     *
     * @return the description of the ResultProducer state, or null if no state is
     *         defined
     */
    String getCompatibilityState();

} // ResultProducer
